﻿//Author:Michal Sporna
//License: https://operationsneakpeek.codeplex.com/license

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Threading;

namespace Util
{
    public static class Cache
    {
        #region public fields
        public enum Screen { Game,ResumedGame, Error, Menu,MapSelector,LevelSelector, None, Options,GameOver,SplashScreen1,LoadingNow,Pause,LoadMap,LoadMapCell,Store };
        public static Screen CurrentScreen;
        public static Screen PreviousScreen;
        
        #endregion

        #region properties
        //all textures
        public static List<Classes.Texture> Textures;
        //sprite batch and graphics
        public static GraphicsDeviceManager graphics;
        public static SpriteBatch spriteBatch;
        //user's graphics device
        public static GraphicsDevice GraphicsDevice;
        //fonts
        public static List<Classes.Font> Fonts;
        //Main Character
        public static Characters.Avatar Avatar;
        //game time
        public static GameTime GameTime;
        //Content manager
        public static ContentManager ContManager;
        //list processed nodes
        public static List<World.Classes.ScannerNode> ProcessedNodes;

        #endregion

        #region flags

        #endregion

        #region private fields
        private static Screen _CurrentScreenToBe;//next current screen

        #endregion

        #region methods

        /// <summary>
        /// set current screen
        /// </summary>
        /// <param name="currentScreen"></param>
        public static void SetCurrentScreen(Screen currentScreen)
        {
            try
            {
                //set previous screen
                Util.Cache.PreviousScreen = Util.Cache.CurrentScreen;
                _CurrentScreenToBe = currentScreen;//just for now set current screen to be. DO not want to set current screen property of cache yet, as the new screen will be drawn, and content is not loaded yet.

                //if (currentScreen != Screen.Menu) //there is nothing to load if it is main menu so don't show loading now screen
                //{
                //    currentScreen = Screen.LoadingNow;
                //}

                //load data
                if (!World.WorldManager.LoadGameData(_CurrentScreenToBe))
                {
                    return; //if I want to cancel this method (SetCurrentScreen) after loading game data, then I'd return false. if false, then return. If true, continue setting this current screen.
                }

                //load content for a specified screen(new screen)
                World.WorldManager.LoadContent(_CurrentScreenToBe);
                //and now, after the content has been loaded, show the screen:
                CurrentScreen = currentScreen;
                _CurrentScreenToBe = Screen.None;
               

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }



        /// <summary>
        /// Add texture to the collection of textures
        /// </summary>
        /// <param name="textureToAdd"></param>
        public static void AddTexture(Texture2D textureToAdd, string name)
        {
            //declare
            bool textureFound = false;

            try
            {
                //declare
                Classes.Texture textureItem;

                //add
                textureItem = new Classes.Texture();
                textureItem.Text2D = textureToAdd;
                textureItem.Name = name;


                //add to the list, if does not exist yet
                foreach (Classes.Texture t in Textures)
                {
                    if (t.Name == name)
                    {
                        textureFound = true;
                        break;
                    }
                }

                if (!textureFound)
                {
                    Textures.Add(textureItem);

                    //remove null values
                    for (int i = 0; i < Textures.Count; i++)
                    {
                        if (Textures[i] == null)
                        {
                            Textures.RemoveAt(i);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }

        }

        /// <summary>
        /// Add font to the collection of fonts
        /// </summary>
        /// <param name="textureToAdd"></param>
        public static void AddFont(SpriteFont font, string name)
        {
            //declare
            Classes.Font fontToAdd;

            //create instance
            fontToAdd = new Classes.Font();
            fontToAdd.FontFace = font;
            fontToAdd.Name = name;

            //add
            Fonts.Add(fontToAdd);


        }


        /// <summary>
        /// Get a texture from cached textures by its name
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static Classes.Texture GetTexture(string name)
        {
            try
            {
                //loop thru all textures and find it
                for (int i=0;i<Cache.Textures.Count;i++)
                {
                    if (Cache.Textures[i].Name.ToLower() == name.ToLower())
                    {
                        return Cache.Textures[i];
                    }
                }

                return null;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return null;
            }

        }

        /// <summary>
        /// Get a font by its name
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static Classes.Font GetFont(string name)
        {
            try
            {
                //loop thru all fonts and find it
                for(int i=0;i<Fonts.Count;i++)
                {
                    if (Fonts[i].Name.ToLower() == name.ToLower())
                    {
                        return Fonts[i];
                    }
                }

                return null;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return null;
            }

        }

        /// <summary>
        /// use sprite batch and draw
        /// </summary>
        public static void Draw(Texture2D texture, Rectangle rectangle, Color color)
        {
            try
            {
                //GraphicsDevice.Clear(Color.Black);

                //if ((bool)Util.Cache.spriteBatch.Tag)
                //{
                //    Util.Cache.spriteBatch.End();
                    
                  
                //}

                //spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend);
                spriteBatch.Tag = true;

                spriteBatch.Draw(texture, rectangle, color);


                //spriteBatch.End();
                //spriteBatch.Tag = false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }

        /// <summary>
        /// use sprite batch and draw
        /// PASS ARRAY OF INTS INSTEAD OF RECTANGLE OBJECT
        /// </summary>
        public static void Draw(Texture2D texture, int[] rectangle, Color color)
        {
            try
            {
                //GraphicsDevice.Clear(Color.Black);

                //if ((bool)Util.Cache.spriteBatch.Tag)
                //{
                //    Util.Cache.spriteBatch.End();


                //}

                //spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend);
                spriteBatch.Tag = true;

                if (rectangle != null)
                {
                    spriteBatch.Draw(texture, new Rectangle(rectangle[0], rectangle[1], rectangle[2], rectangle[3]), Color.White);
                }

                //spriteBatch.End();
                //spriteBatch.Tag = false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }

        /// <summary>
        /// use sprite batch and draw
        /// </summary>
        public static void Draw(SpriteBatch sp,Texture2D texture, Rectangle rectangle, Color color)
        {
            try
            {
                //GraphicsDevice.Clear(Color.Black);

                //if ((bool)Util.Cache.spriteBatch.Tag)
                //{
                //    Util.Cache.spriteBatch.End();
                //}

                sp.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                //sp.Tag = true;

                sp.Draw(texture, rectangle, color);


                sp.End();
                sp.Dispose();
                //spriteBatch.Tag = false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }


        /// <summary>
        /// use sprite batch and draw with effects
        /// </summary>
        public static void Draw(Texture2D texture, Rectangle rectangle, Color color,SpriteSortMode sortMode, BlendState blendState, SpriteEffects effects)
        {
            try
            {
                //GraphicsDevice.Clear(Color.Black);

                if ((bool)Util.Cache.spriteBatch.Tag)
                {
                    Util.Cache.spriteBatch.End();
                }

                spriteBatch.Begin(sortMode, blendState);
                spriteBatch.Tag = true;

                spriteBatch.Draw(texture, rectangle, color);


                spriteBatch.End();
                spriteBatch.Tag = false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }

        /// <summary>
        /// use sprite batch and draw
        /// </summary>
        public static void DrawWithRotation(Texture2D texture, Rectangle rectangle, Color color, float rotation)
        {
            try
            {
                //GraphicsDevice.Clear(Color.Black);

                if ((bool)Util.Cache.spriteBatch.Tag)
                {
                    Util.Cache.spriteBatch.End();
                }

                spriteBatch.Begin();
                spriteBatch.Tag = true;

                //draw
                spriteBatch.Draw(texture, rectangle,null, color,rotation,new Vector2(0,0),SpriteEffects.None,0);


                spriteBatch.End();
                spriteBatch.Tag = false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }


        /// <summary>
        /// Draw rectangle
        /// </summary>
        /// <param name="rectangle"></param>
        /// <param name="color"></param>
        public static void DrawRectangle(Rectangle rectangle, Color color)
        {
            try
            {

                if ((bool)Util.Cache.spriteBatch.Tag)
                {
                    Util.Cache.spriteBatch.End();
                }

                spriteBatch.Begin();
                spriteBatch.Tag = true;

                //draw rectangle
                spriteBatch.Draw(GetTexture("line").Text2D, new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, 1), color);
                spriteBatch.Draw(GetTexture("line").Text2D, new Rectangle(rectangle.Left, rectangle.Bottom, rectangle.Width, 1), color);
                spriteBatch.Draw(GetTexture("line").Text2D, new Rectangle(rectangle.Left, rectangle.Top,1, rectangle.Height), color);
                spriteBatch.Draw(GetTexture("line").Text2D, new Rectangle(rectangle.Right, rectangle.Top,1, rectangle.Height+ 1), color);


                spriteBatch.End();
                spriteBatch.Tag = false;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }

       
        /// <summary>
        /// Draw a line between the two supplied points.
        /// </summary>
        /// <param name="start">Starting point.</param>
        /// <param name="end">End point.</param>
        /// <param name="color">The draw color.</param>
        public static void DrawLine(Vector2 start, Vector2 end, Color color)
        {
            try
            {
                if ((bool)Util.Cache.spriteBatch.Tag)
                {
                    Util.Cache.spriteBatch.End();
                }

                spriteBatch.Begin();
                spriteBatch.Tag = true;

                float length = (end - start).Length();
                float rotation = (float)Math.Atan2(end.Y - start.Y, end.X - start.X);
                spriteBatch.Draw(GetTexture("line").Text2D, start, null, color, rotation, Vector2.Zero, new Vector2(length, 1), SpriteEffects.None, 0);

                spriteBatch.End();
                spriteBatch.Tag = false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


  
        /// <summary>
        /// Fill rectangle
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="color"></param>
        public static void FillRectangle(Texture2D texture,Rectangle rect, Color color)
        {
            try
            {

                if ((bool)Util.Cache.spriteBatch.Tag)
                {
                    Util.Cache.spriteBatch.End();
                }

                spriteBatch.Begin();
                spriteBatch.Tag = true;

                //draw rectangle
                spriteBatch.Draw(texture, rect, color);

               
                spriteBatch.End();
                spriteBatch.Tag = false;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }



        }

        /// <summary>
        /// use sprite batch and draw
        /// </summary>
        public static void DrawString(SpriteFont fontFace, string text, Vector2 location, float scale, Color color)
        {
            try
            {
                //if ((bool)Util.Cache.spriteBatch.Tag)
                //{
                //    Util.Cache.spriteBatch.End();
                //}

                //Util.Cache.spriteBatch.Begin();

                Util.Cache.spriteBatch.DrawString(fontFace, text, location, color);
                
                

                //Util.Cache.spriteBatch.End();
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;

            }


        }


        /// <summary>
        /// use sprite batch and draw with effects
        /// </summary>
        public static void DrawString(SpriteFont fontFace, string text, Vector2 location, float scale, Color color, SpriteSortMode sortMode, BlendState blendState, SpriteEffects effects)
        {
            try
            {
                if ((bool)Util.Cache.spriteBatch.Tag)
                {
                    Util.Cache.spriteBatch.End();
                }

                Util.Cache.spriteBatch.Begin(sortMode,blendState);

                Util.Cache.spriteBatch.DrawString(fontFace, text, location, color);



                Util.Cache.spriteBatch.End();
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;

            }


        }

        #endregion
    }
}
